package util.common;

import com.google.common.base.Joiner;
import com.google.common.collect.Maps;
import com.sun.istack.internal.NotNull;
import com.sun.istack.internal.Nullable;
import util.exception.MyUtilException;

import java.util.Map;

import static org.joor.Reflect.on;

/**
 * @author ：Sei
 * @date ：Created in 2020/1/6 20:15
 * @description：ioc容器
 * @modified By：
 * @version: $
 */
public enum IocContainer {
    /**
     *  单例对象池的唯一实例
     */
    INSTANCE;
    /**
     * 对象池
     */
    private static final Map<String, Object> POOL = Maps.newConcurrentMap();
    /**
     * 键连接符
     */
    private static final char CONJUNCTION = '#';


    //region 实例方法

    /**
     * 获取类的实例，如果对象池中不存在则创建对象并返回
     * @param clazz
     * @param params
     * @param <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    @NotNull
    public  <T> T get(@NotNull Class<T> clazz, @Nullable Object... params){
        final String key = genKey(clazz.getName(), params);
        T res = (T) POOL.get(key);
        if(null == res){
            synchronized (IocContainer.class){
                res = (T) POOL.get(key);
                if(null == res){
                    res = newInstance(clazz, params);
                    POOL.put(key, res);
                }
            }
        }
        return res;
    }

    /**
     * 清空对象池
     * @return
     */
    public boolean clear(){
        try{
            POOL.clear();
            return true;
        }
        catch (Exception e){
            return false;
        }
    }

    /**
     * 将指定对象实例放入对象池中，但是缺陷是可能会覆盖存在的键，需要改进
     * @param value
     */
    public void put(@NotNull Object value){
        POOL.put(value.getClass().getName(), value);
    }

    /**
     * 获取对象池大小
     * @return
     */
    public long getPoolSize(){
        return POOL.size();
    }
    //endregion

    // ------------------------------------------------------------------------------------------- Private method start
    //region 静态方法

    /**
     * 生成对象池的键值
     * @param className
     * @param params
     * @return
     */
    private static String genKey(@NotNull String className, @Nullable Object... params){
        if(null == params || params.length == 0){
            return className;
        }
        final StringBuilder sb = new StringBuilder().append(className).append(CONJUNCTION);
        return Joiner.on(CONJUNCTION).appendTo(sb, params).toString();
    }

    private static Class<?>[] getClasses(Object... objects) {
        Class<?>[] classes = new Class<?>[objects.length];
        Object obj;
        int i = 0;
        while(i < objects.length){
            obj = objects[i];
            classes[i++] = (null != obj) ? obj.getClass() : Object.class;
        }
        return classes;
    }

    private static <T> T newInstance(Class<T> clazz, Object... params) {
        // 获取参数的class数组，构建构造器，如果构造器不为空则填入参数构建新对象
        if(null == params || params.length == 0){
            try{
                return on(clazz).create().get();
            }
            catch (Exception e){
                throw new MyUtilException("Utils Error: NoArgsConstructor error!");
            }
        }
        else{
            try{
                return on(clazz).create(params).get();
            }
            catch (Exception e){
                throw new MyUtilException("Utils Error: ArgsConstructor error!");
            }
        }
    }
    //endregion
    // ------------------------------------------------------------------------------------------- Private method end
}
